package com.clhbolg.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clhbolg.constant.RabbitMQConstant;
import com.clhbolg.domain.Comment;
import com.clhbolg.domain.UserInfo;
import com.clhbolg.domain.bo.CommentBo;
import com.clhbolg.domain.vo.CommentVo;
import com.clhbolg.enums.CommentTypeEnum;
import com.clhbolg.mapper.ArticleMapper;
import com.clhbolg.mapper.CommentMapper;
import com.clhbolg.mapper.TalkMapper;
import com.clhbolg.mapper.UserInfoMapper;
import com.clhbolg.model.dto.*;
import com.clhbolg.model.vo.request.CommentVO;
import com.clhbolg.model.vo.request.ConditionVO;
import com.clhbolg.model.vo.request.ReviewVO;
import com.clhbolg.service.ICommentService;
import com.clhbolg.service.IWebsiteConfigService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author cailinhu
 * @date 2023-02-08
 */
@RequiredArgsConstructor
@Service
@DS("slave")
public class CommentServiceImpl implements ICommentService {

    private final CommentMapper baseMapper;

    @Value("${website.url}")
    private String websiteUrl;
    @Autowired
    IWebsiteConfigService websiteConfigService;
    @Resource
    UserInfoMapper userInfoMapper;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Resource
    CommentMapper commentMapper;
    @Resource
    ArticleMapper articleMapper;
    @Resource
    TalkMapper talkMapper;

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;
    /**
     * 查询【请填写功能名称】
     */
    @Override
    public CommentVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询【请填写功能名称】列表
     */
    @Override
    public TableDataInfo<CommentVo> queryPageList(CommentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Comment> lqw = buildQueryWrapper(bo);
        Page<CommentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询【请填写功能名称】列表
     */
    @Override
    public List<CommentVo> queryList(CommentBo bo) {
        LambdaQueryWrapper<Comment> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Comment> buildQueryWrapper(CommentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Comment> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getUserId() != null, Comment::getUserId, bo.getUserId());
        lqw.eq(bo.getTopicId() != null, Comment::getTopicId, bo.getTopicId());
        lqw.eq(StringUtils.isNotBlank(bo.getCommentContent()), Comment::getCommentContent, bo.getCommentContent());
        lqw.eq(bo.getReplyUserId() != null, Comment::getReplyUserId, bo.getReplyUserId());
        lqw.eq(bo.getParentId() != null, Comment::getParentId, bo.getParentId());
        lqw.eq(bo.getType() != null, Comment::getType, bo.getType());
        lqw.eq(bo.getIsDelete() != null, Comment::getIsDelete, bo.getIsDelete());
        lqw.eq(bo.getIsReview() != null, Comment::getIsReview, bo.getIsReview());
        return lqw;
    }

    /**
     * 新增【请填写功能名称】
     */
    @Override
    public Boolean insertByBo(CommentBo bo) {
        Comment add = BeanUtil.toBean(bo, Comment.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改【请填写功能名称】
     */
    @Override
    public Boolean updateByBo(CommentBo bo) {
        Comment update = BeanUtil.toBean(bo, Comment.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Comment entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除【请填写功能名称】
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public List<CommentDTO> listTopSixComments() {
        return baseMapper.listTopSixComments();
    }

    @Override
    public TableDataInfo<CommentDTO> listComments(CommentVO commentVO,PageQuery pageQuery) {
        Page<CommentDTO>  rootComments=baseMapper.listRootComments(commentVO,pageQuery.build());
        //根据根评论找到对应的子回复以及评论人等信息
        List<Long> commentIds = rootComments.getRecords().stream()
            .map(CommentDTO::getId)
            .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(commentIds)){
            List<ReplyDTO> replyDTOS = baseMapper.listReplies(commentIds);
            //按根id分组
            Map<Integer, List<ReplyDTO>> replyMap = replyDTOS.stream()
                .collect(Collectors.groupingBy(ReplyDTO::getParentId));
            rootComments.getRecords().forEach(item -> item.setReplyDTOs(replyMap.get(item.getId())));
        }
        return TableDataInfo.build(rootComments);
    }

    @Override
    public void saveComment(CommentVO commentVO) {
        Comment comment = Convert.convert(Comment.class, commentVO);
        //判断是否开启了审核机制
        WebsiteConfigDTO websiteConfig = websiteConfigService.getWebsiteConfig();
        Integer isCommentReview = websiteConfig.getIsCommentReview();
        comment.setIsReview(isCommentReview==1?0:1);
        Long userId = LoginHelper.getUserId();
        comment.setUserId(userId);
        baseMapper.insert(comment);
        //是否需要邮箱推送
        String nickName = LoginHelper.getLoginUser().getNickName();
        if (websiteConfig.getIsEmailNotice()==1) {
            CompletableFuture.runAsync(() -> notice(comment, nickName),threadPoolTaskExecutor);
        }
    }

    /**
     * 邮箱发送提醒
     * @param comment
     * @param nickName
     */
    private void notice(Comment comment, String nickName) {
        //1.如果是回复自己的，不用发送
        if (comment.getUserId().equals(comment.getReplyUserId())) {
            if (Objects.nonNull(comment.getParentId())) {
                Comment parentComment = baseMapper.selectById(comment.getParentId());
                if (parentComment.getUserId().equals(comment.getUserId())) {
                    return;
                }
            }
        }

        //2.如果是管理员，博主本人并且不是回复评论的不用发送
//        if (comment.getUserId().equals(BLOGGER_ID) && Objects.isNull(comment.getParentId())) {
//            return;
//        }
        if (Objects.nonNull(comment.getParentId())) {
            Comment parentComment = baseMapper.selectById(comment.getParentId());
            if (!comment.getReplyUserId().equals(parentComment.getUserId())
                && !comment.getReplyUserId().equals(comment.getUserId())) {
                UserInfo userInfo = userInfoMapper.selectById(comment.getUserId());
                UserInfo replyUserinfo = userInfoMapper.selectById(comment.getReplyUserId());
                Map<String, Object> map = new HashMap<>();
                String topicId = Objects.nonNull(comment.getTopicId()) ? comment.getTopicId().toString() : "";
                String url = websiteUrl + CommentTypeEnum.getCommentPath(comment.getType()) + topicId;
                map.put("content", userInfo.getNickname() + "在" + Objects.requireNonNull(CommentTypeEnum.getCommentEnum(comment.getType())).getDesc()
                    + "的评论区@了你，"
                    + "<a style=\"text-decoration:none;color:#12addb\" href=\"" + url + "\">点击查看</a>");
                EmailDTO emailDTO = EmailDTO.builder()
                    .email(replyUserinfo.getEmail())
                    .subject("@提醒")
                    .template("common.html")
                    .commentMap(map)
                    .build();
                rabbitTemplate.convertAndSend(RabbitMQConstant.EMAIL_EXCHANGE, "*",emailDTO );
            }
            if (comment.getUserId().equals(parentComment.getUserId())) {
                return;
            }
        }

        String title;
        Long userId = 1L;
        String topicId = Objects.nonNull(comment.getTopicId()) ? comment.getTopicId().toString() : "";
        if (Objects.nonNull(comment.getReplyUserId())) {
            userId = comment.getReplyUserId();
        } else {
            switch (Objects.requireNonNull(CommentTypeEnum.getCommentEnum(comment.getType()))) {
                case ARTICLE:
                    userId = articleMapper.selectById(comment.getTopicId()).getUserId();
                    break;
                case TALK:
                    userId = talkMapper.selectById(comment.getTopicId()).getUserId();
                default:
                    break;
            }
        }
        if (Objects.requireNonNull(CommentTypeEnum.getCommentEnum(comment.getType())).equals(CommentTypeEnum.ARTICLE)) {
            title = articleMapper.selectById(comment.getTopicId()).getArticleTitle();
        } else {
            title = Objects.requireNonNull(CommentTypeEnum.getCommentEnum(comment.getType())).getDesc();
        }
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(userInfo.getEmail())) {
            EmailDTO emailDTO = getEmailDTO(comment, userInfo, nickName, topicId, title);
            rabbitTemplate.convertAndSend(RabbitMQConstant.EMAIL_EXCHANGE, "*", emailDTO);
        }

    }


    private EmailDTO getEmailDTO(Comment comment, UserInfo userInfo, String fromNickname, String topicId, String title) {
        EmailDTO emailDTO = new EmailDTO();
        Map<String, Object> map = new HashMap<>();
        if (comment.getIsReview().equals(1)) {
            String url = websiteUrl + CommentTypeEnum.getCommentPath(comment.getType()) + topicId;
            if (Objects.isNull(comment.getParentId())) {
                emailDTO.setEmail(userInfo.getEmail());
                emailDTO.setSubject("评论提醒");
                emailDTO.setTemplate("owner.html");
                String createTime = DateUtil.format(comment.getCreateTime(),DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
                map.put("time", createTime);
                map.put("url", url);
                map.put("title", title);
                map.put("nickname", fromNickname);
                map.put("content", comment.getCommentContent());
            } else {
                Comment parentComment = commentMapper.selectOne(new LambdaQueryWrapper<Comment>().select(Comment::getUserId, Comment::getCommentContent, Comment::getCreateTime).eq(Comment::getId, comment.getParentId()));
                if (!userInfo.getId().equals(parentComment.getUserId())) {
                    userInfo = userInfoMapper.selectById(parentComment.getUserId());
                }
                emailDTO.setEmail(userInfo.getEmail());
                emailDTO.setSubject("评论提醒");
                emailDTO.setTemplate("user.html");
                map.put("url", url);
                map.put("title", title);
                String createTime = DateUtil.format(parentComment.getCreateTime(),DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
                map.put("time", createTime);
                map.put("toUser", userInfo.getNickname());
                map.put("fromUser", fromNickname);
                map.put("parentComment", parentComment.getCommentContent());
                if (!comment.getReplyUserId().equals(parentComment.getUserId())) {
                    UserInfo mentionUserInfo = userInfoMapper.selectById(comment.getReplyUserId());
                    if (Objects.nonNull(mentionUserInfo.getWebsite())) {
                        map.put("replyComment", "<a style=\"text-decoration:none;color:#12addb\" href=\""
                            + mentionUserInfo.getWebsite()
                            + "\">@" + mentionUserInfo.getNickname() + " " + "</a>" + parentComment.getCommentContent());
                    } else {
                        map.put("replyComment", "@" + mentionUserInfo.getNickname() + " " + parentComment.getCommentContent());
                    }
                } else {
                    map.put("replyComment", comment.getCommentContent());
                }
            }
        } else {
            String adminEmail = userInfoMapper.selectById(1L).getEmail();
            emailDTO.setEmail(adminEmail);
            emailDTO.setSubject("审核提醒");
            emailDTO.setTemplate("common.html");
            map.put("content", "您收到了一条新的回复，请前往后台管理页面审核");
        }
        emailDTO.setCommentMap(map);
        return emailDTO;
    }
    @Override
    public List<ReplyDTO> listRepliesByCommentId(Long commentId) {
        return baseMapper.listReplies(Arrays.asList(commentId));
    }

    @Override
    public TableDataInfo<CommentAdminDTO> listCommentsAdmin(ConditionVO conditionVO, PageQuery pageQuery) {
        //TODO 待完成！
        Page<CommentAdminDTO> comments=baseMapper.listCommentsAdmin(conditionVO,pageQuery.build());

        return TableDataInfo.build(comments);
    }

    /**
     * 评论审核
     * @param reviewVO
     */
    @Override
    public void updateCommentsReview(ReviewVO reviewVO) {
        LambdaUpdateWrapper<Comment> wrapper = Wrappers.lambdaUpdate(Comment.class);
        wrapper.set(Comment::getIsReview,reviewVO.getIsReview()).in(Comment::getId,reviewVO.getIds());
        baseMapper.update(null,wrapper);
    }

    @Override
    public void delCommentsByIds(List<Long> ids) {
        LambdaUpdateWrapper<Comment> wrapper = Wrappers.lambdaUpdate(Comment.class);
        wrapper.set(Comment::getIsDelete,1).in(Comment::getId,ids);
        baseMapper.update(null,wrapper);
    }
}
